#include<reg51.h>
#define uchar unsigned char
#define uint unsigned int
#define temp P1
  
sbit rs=P2^5;  // 指令/数据选择
sbit rw=P2^6;  // 读/写选择
sbit e=P2^7;   // e由1到0，执行指令

//变量定义
uint key=0;
uchar press_key=0;
uchar num=0;

//函数声明
void delay(uchar x); //延时函数
void delay1(uint t);  //延时函数
uchar getkeys(); //按键函数
											 
void write_com(uchar com); //写指令函数
void write_dat(uchar dat); //写数据函数
void init_1602();  // 初始化


main()
{
		init_1602();
		write_com(0x80);
		write_dat('k');
		write_dat('e');
		write_dat('y');
	while(1)
	{
       temp=0xf0;
//       if(temp!=0xf0)    //检测是否有键按下
//       {
//          delay(5);    //延时消抖
          if(temp!=0xf0)   //再次检测是否有键按下
          {
             temp=0xf0;     //对应IO口拉高，以便检测
             switch(temp)   //先确定行
             {
                case 0x70: num=1;   write_com(0x84); write_dat('8');break;   //第一行
                case 0xb0: num=5;   write_com(0x84); write_dat('8');break;   //第二行
                case 0xd0: num=9;   write_com(0x84); write_dat('8');break;   //第三行
                case 0xe0: num=13;  write_com(0x84); write_dat('8');break;   //第四行
             }
             temp=0x0f;     //对应IO口拉高，以便检测
             switch(temp)   //再确定列
             {
                case 0x07: num=num+0;  write_com(0x84); write_dat('8');break;   //第一列
                case 0x0b: num=num+1;  write_com(0x84); write_dat('8');break;   //第二列
                case 0x0d: num=num+2;  write_com(0x84); write_dat('8');break;   //第三列
                case 0x0e: num=num+3;  write_com(0x84); write_dat('8');break;   //第四列
             }
						
						 //display(num);   //结合行列扫描的值得出按键对应的数值，并返回
          }
//       }
       write_com(0x86); write_dat('x');//display(num);   //结合行列扫描的值得出按键对应的数值，并返回
    }
		
/*		
		press_key=getkeys(); //获取按键值
		switch(press_key)
		{
			case 0xfe: key=1; write_com(0x84); write_dat('1'); break; //1行1列
			case 0x12: key=5; write_com(0x84); write_dat('5'); break; //2行1列
			case 0x14: key=9; write_com(0x84); write_dat('9'); break; //3行1列
			case 0x18: key=13; write_com(0x84); write_dat('1'); write_dat('3'); break; //4行1列
			
			case 0x21: key=2; break; //1行2列
			case 0x22: key=6; break; //2行2列
			case 0x24: key=10; break; //3行2列
			case 0x28: key=14; break; //4行2列

			case 0x41: key=3; break; //1行3列
			case 0x42: key=7; break; //2行3列
			case 0x44: key=11; break; //3行3列
			case 0x48: key=15; break; //4行3列

			case 0x81: key=4; break; //1行3列
			case 0x82: key=8; break; //2行3列
			case 0x84: key=12; break; //3行3列
			case 0x88: key=16; break; //4行3列
			default: write_com(0x84); write_dat('0'); break;
		}
 }
 */
}

//获取按键值的函数
uchar getkeys()
{
	uchar x, y;
	P1=0xf0;
	if((P1&0xf0)!=0xf0) //表示有键按下
	{
		delay(20); //延时去抖动
		if((P1&0xf0)!=0xf0) //再次判断
		{
			x=0xfe;
			while(x&0x10!=0) //行线判定是否结束
			{
				P1=x;
				if((P1&0xf0)!=0xf0) //列线发生电平跳变
				{
					y=(P1&0xf0)|0x0f;
					return (0xfe);
				}
				else
					x=(x<<1)|0x01; //循环左移，判定下一行线
			}/*
			for(;;) //等待按键释放
			{
				if((P1&0xf0)==0xf0) //表示没有按下
					break;
			}*/
		}
	}
	//return(0);
}

//延时函数
void delay(uchar x)
{
	uchar a, b;
	for(a=x;a>0;a--)
		for(b=200;b>0;b--);
}

void delay1(uint t)
{
    while(--t);
}

void write_com(uchar com) //写指令函数
{
    rs=0;        //选择指令寄存器
    rw=0;        //选择写操作
    P0=com;      //让P1口的8个脚获取指令参数
    delay1(100); 
    e=1;         //e由1到0，执行指令
    delay1(100);
    e=0;
}

void write_dat(uchar dat)
{
    rs=1;         //选择数据寄存器
    rw=0;         //选择写操作
    P0=dat;       //让P1口的8个脚获取数据参数
    delay1(100);
    e=1;
    delay1(100);
    e=0;
}

void init_1602()
{
    write_com(0x38);  //功能设置指令：选择8位总线，两行显示方式，5x8点阵
    write_com(0x0c);  //打开屏幕显示功能，没有光标，也没有结尾闪烁
    write_com(0x06);  //写完字符后，光标右移，屏幕移动
    write_com(0x01);  //清屏 
}


/*
//显示函数
void display(uchar key)
{
	P1=dispcode[key%10]; //个位数
	P0=sel;
	sel=sel<<1;
	P1=0x00; //数码管去重影
	P1=dispcode[buffer[i]/10]; //十位数
	P0=sel;
	sel=sel<<1;
	P1=0x00;
	if(sel==0x40) //0x40: 0100 0000
		sel=0x01;	//0x01: 0000 0001
}
*/